package com.zp.base.admin.config;


import com.zp.base.admin.security.*;
import com.zp.base.admin.service.UserService;
import freemarker.ext.jsp.TaglibFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * @author ZhangPeng
 * @email zhangpeng98@aliyun.com
 * @create 2021-03-03 17:01
 */
//@EnableGlobalMethodSecurity：配置开启注解式授权 开启基于方法的安全认证机制，也就是说在web层的controller启用注解机制的安全确认，
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    UserService userService;
    @Autowired
    MyAuthenticationFailureHandler authenticationFailureHandler;
    @Autowired
    MyAuthenticationSuccessHandler authenticationSuccessHandler;
    @Autowired
    ImageCodeAuthenticationFilter imageCodeAuthenticationFilter;
    @Autowired
    FreeMarkerConfigurer configurer;
    @Autowired
    MyLogoutSuccessHandler logoutSuccessHandler;


    /**
     * freemark使用Spring Security标签配置
     */
    @PostConstruct
    public void freeMarkerConfigurer() {
        List<String> tlds = new ArrayList<String>();
        tlds.add("/static/tags/security.tld");
        TaglibFactory taglibFactory = configurer.getTaglibFactory();
        taglibFactory.setClasspathTlds(tlds);
        if(taglibFactory.getObjectWrapper() == null) {
            taglibFactory.setObjectWrapper(configurer.getConfiguration().getObjectWrapper());
        }
    }

    /**
     * 授权请求
     * 我们的示例仅要求对用户进行身份验证，并且对应用程序中的每个URL都进行了身份验证。
     * 我们可以通过向我们的http.authorizeRequests()方法添加多个子级来为URL指定自定义要求。
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/system/login", "/captcha/generateCaptcha", "/admin/css/**", "/admin/fonts/**", "/admin/images/**", "/admin/js/**").permitAll()
                .anyRequest().authenticated()
                .and()
                //登录配置
                .formLogin()
                .loginPage("/system/login")
                .loginProcessingUrl("/adminLogin")
                .failureHandler(authenticationFailureHandler)
                .successHandler(authenticationSuccessHandler)
                .and()
                //在登录拦截前校验验证码
                .addFilterBefore(imageCodeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                //springSecurity  是会对 post请求进行验证的,导致会403，关闭csrf即可
                .csrf().disable()
                //登出配置
                .logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    //配置认证管理器
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
    }
}
